/* $Id$ */
package org.crazydays.gameplan.model;


import java.io.File;
import java.io.IOException;

import org.junit.*;
import static org.junit.Assert.*;

import static org.easymock.EasyMock.*;
import static org.easymock.classextension.EasyMock.*;

import org.crazydays.gameplan.db.Database;
import org.crazydays.gameplan.map.GameMap;
import org.crazydays.gameplan.map.GridType;
import org.crazydays.gameplan.map.IGameMap;
import org.crazydays.junit.TestHelper;

/**
 * ModelUnitTest
 */
public class ModelUnitTest
{
    /** test helper */
    protected TestHelper testHelper = new TestHelper(ModelUnitTest.class);

    /**
     * Cleanup test helper.
     */
    @After
    public void tearDown()
    {
        testHelper.tearDown();
    }

    /**
     * Test createDatabase().
     */
    @Test
    public void testCreateDatabase()
    {
        // mocks
        IDatabaseObserver observer = createMock(IDatabaseObserver.class);

        // expect
        observer.opened(isA(Database.class));

        // replay
        replay(observer);

        // setup
        Model model = new Model();
        model.addDatabaseObserver(observer);

        // test
        model.createDatabase();

        // tear down
        model.removeDatabaseObserver(observer);

        // verify
        verify(observer);

        assertNotNull("model.database", model.database);
    }

    /**
     * Test openDatabase(File).
     * 
     * @throws IOException
     */
    @Test
    public void testOpenDatabase()
        throws IOException
    {
        // objects
        File file = testHelper.copy(testHelper.getSandbox(), "ThreeMaps.gp1");

        // mocks
        IDatabaseObserver observer = createMock(IDatabaseObserver.class);

        // expect
        observer.opened(isA(Database.class));

        // replay
        replay(observer);

        // setup
        Model model = new Model();
        model.addDatabaseObserver(observer);

        // test
        model.openDatabase(file);

        // tear down
        model.removeDatabaseObserver(observer);

        // verify
        verify(observer);

        assertNotNull("model.database", model.database);
    }

    /**
     * Test openDatabase(File).
     * 
     * @throws IOException
     */
    @Test(expected = IllegalArgumentException.class)
    public void testOpenDatabase_null()
        throws IOException
    {
        // setup
        Model model = new Model();

        // test
        model.openDatabase(null);
    }

    /**
     * Test closeDatabase().
     */
    @Test
    public void testCloseDatabase()
    {
        // objects
        Database database = new Database();

        // mocks
        IDatabaseObserver observer = createMock(IDatabaseObserver.class);

        // expect
        observer.closed(isA(Database.class));

        // replay
        replay(observer);

        // setup
        Model model = new Model();
        model.database = database;
        model.addDatabaseObserver(observer);

        // test
        model.closeDatabase();

        // tear down
        model.removeDatabaseObserver(observer);

        // verify
        verify(observer);

        assertNull("model.database", model.database);
    }

    /**
     * Test addGameMap(IGameMap).
     */
    @Test(expected = IllegalStateException.class)
    public void testAddGameMap_null_database()
    {
        // mocks
        IGameMap gameMap = createMock(IGameMap.class);

        // replay
        replay(gameMap);

        // setup
        Model model = new Model();

        // test
        model.addGameMap(gameMap);
    }

    /**
     * Test addGameMap(IGameMap).
     */
    @Test
    public void testAddGameMap()
    {
        // mocks
        IGameMapObserver observer = createMock(IGameMapObserver.class);
        IGameMap gameMap = createMock(IGameMap.class);
        Database database = createMock(Database.class);

        // expect
        database.addGameMap(gameMap);
        observer.added(gameMap);

        // replay
        replay(observer, gameMap, database);

        // setup
        Model model = new Model();
        model.addGameMapObserver(observer);
        model.database = database;

        // test
        model.addGameMap(gameMap);

        // verify
        verify(observer, gameMap, database);
        model.removeGameMapObserver(observer);
    }

    /**
     * Test getGameMap(String).
     */
    @Test
    public void testGetGameMap()
    {
        // objects
        Database database = new Database();
        database.addGameMap(new GameMap("one"));
        database.addGameMap(new GameMap("two"));

        // setup
        Model model = new Model();
        model.database = database;

        // test
        IGameMap result = model.getGameMap("two");

        // verify
        assertNotNull("result == null");
        assertEquals("result", "two", result.getName());
    }

    /**
     * Test getGameMap(String).
     */
    @Test
    public void testGetGameMap_no_map()
    {
        // objects
        Database database = new Database();
        database.addGameMap(new GameMap("one"));
        database.addGameMap(new GameMap("two"));

        // setup
        Model model = new Model();
        model.database = database;

        // test
        IGameMap result = model.getGameMap("three");

        // verify
        assertNull("result == null", result);
    }

    /**
     * Test getGameMap(String).
     */
    @Test(expected = IllegalStateException.class)
    public void testGetGameMap_null_database()
    {
        // objects
        Database database = null;

        // setup
        Model model = new Model();
        model.database = database;

        // test
        model.getGameMap("three");
    }

    /**
     * Test getGameMap(String).
     */
    @Test(expected = IllegalArgumentException.class)
    public void testGetGameMap_null_argument()
    {
        // objects
        Database database = new Database();
        database.addGameMap(new GameMap("one"));
        database.addGameMap(new GameMap("two"));

        // setup
        Model model = new Model();
        model.database = database;

        // test
        model.getGameMap(null);
    }

    /**
     * Test save.
     * 
     * @throws IOException
     */
    @Test
    public void testSave()
        throws IOException
    {
        // database
        Database database = new Database();
        database.setName("aname");
        database.addGameMap(new GameMap("grid", 480, 640, GridType.SQUARE, 20));
        database.addGameMap(new GameMap("hex", 480, 640, GridType.HEXAGON, 20));
        database.addGameMap(new GameMap("iso", 480, 640, GridType.DIAMOND, 20));

        File saveFile = new File(testHelper.getSandbox(), "test.gp1");

        // setup
        Model model = new Model();
        model.database = database;
        model.saveFile = saveFile;

        // test
        model.save();

        // verify
        assertTrue("saveFile", saveFile.exists());
    }

    /**
     * Test save.
     * 
     * @throws IOException
     */
    @Test(expected = IllegalStateException.class)
    public void testSave_null_database()
        throws IOException
    {
        // database
        Database database = null;

        File saveFile = new File(testHelper.getSandbox(), "test.gp1");

        // setup
        Model model = new Model();
        model.database = database;
        model.saveFile = saveFile;

        // test
        model.save();
    }

    /**
     * Test save.
     * 
     * @throws IOException
     */
    @Test(expected = IllegalStateException.class)
    public void testSave_null_file()
        throws IOException
    {
        // database
        Database database = new Database();
        database.setName("aname");
        database.addGameMap(new GameMap("grid", 480, 640, GridType.SQUARE, 20));
        database.addGameMap(new GameMap("hex", 480, 640, GridType.HEXAGON, 20));
        database.addGameMap(new GameMap("iso", 480, 640, GridType.DIAMOND, 20));

        // setup
        Model model = new Model();
        model.database = database;

        // test
        model.save();
    }
}
